
package ubi3d.Data;


import java.awt.Color;
import java.util.ArrayList;

/**
 * Competitor class, implements filtering and various statistics functions
 *
 * Copyright (C) 2008 BBC Research, Sam Davies, <Sam.Davies@bbc.co.uk>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
public class Competitor {

    private ArrayList<Float[]> lastTen;             //Array:{x,y,z,timecode}
    private double currentSpeed = 0;
    private double totalDistance = 0;
    private int tagID;
    private double avgSpeed = 0;
    private double totalTime = 0;
    private Color thisColour;
    private double statsX,  statsY;
    private int orderOfAppearence;
    private boolean showPlayer = true;
    private double caloriesBurnt = 0;
    private Float[] boundaryCordinates;
    private double percentageInLeft = 0;
    private double percentageInRight = 0;
    private double timesInRight = 0;
    private double timesInLeft = 0;
  //  private LocationMessage otherPlayerMessage = null;
    private double error = 0;
 //   private LocationMessage currentMessage = null;
    private ArrayList<Float[]> lastTwoAveraged = new ArrayList<Float[]>();
    private Float[] newCoord;
    private Float[] oldCoord;

    public Competitor(int tagID, Float[] firstCoord) {
        lastTen = new ArrayList<Float[]>();
        this.addCoord(firstCoord, 1);
        this.tagID = tagID;
    }

    public Competitor(int tagID, Float[] firstCoord, Float[] boundaryCordinates) {
        lastTen = new ArrayList<Float[]>();
        this.addCoord(firstCoord, 1);
        this.tagID = tagID;
        this.boundaryCordinates = boundaryCordinates;
    }
/**
    public Competitor(int tagID, Float[] firstCoord, ArrayList<Float[]> boundaryCordinates, LocationMessage currentMessage) {
        lastTen = new ArrayList<Float[]>();
        this.addCoord(firstCoord, 1);
        this.tagID = tagID;
        this.boundaryCordinates = boundaryCordinates;
        //this.currentMessage = currentMessage;
    }
**/
    public void addCoord(Float[] latest, int filterFunction) {
        lastTen.add(0, latest);

        if (lastTen.size() > 1) {
            if (lastTen.size() >= filterFunction) {
                for (int i = filterFunction - 1; i < lastTen.size(); i++) {
                    lastTen.remove(i);
                }
                lastTen.trimToSize();

            }
            totalDistance += addDistance();
            currentSpeed = currentSpeed();
            avgSpeed = averageSpeed();
            caloriesBurnt += caloriesBurnt(currentSpeed);
            calculatePercentages();
        }

    }

    private void lowPassFilter() {
        if (lastTen.size() > 1) {
            if (addDistance() > 5) {
                lastTwoAveraged.add(lastTwoAveraged.get(1));
            }

        }
    }

    public Float[] getAvgedCoordsStep() {


        float avgX = 0;
        float avgY = 0;
        float avgZ = 0;
        int totalPoints = 0;
        for (int i = 0; i < lastTen.size(); i++) {
            for (int j = 0; j < lastTen.size() - i; j++) {
                avgX += lastTen.get(i)[0];
                avgY += lastTen.get(i)[1];
                avgZ += lastTen.get(i)[2];
                totalPoints++;
            }
        }
        avgX = avgX / totalPoints;
        avgY = avgY / totalPoints;
        avgZ = avgZ / totalPoints;

        if (oldCoord != null) {
            oldCoord = newCoord;

        }
        newCoord = new Float[]{ avgX,  avgY,  avgZ};
        if (oldCoord == null) {
            oldCoord = newCoord;
        }

        if (lastTwoAveraged.size() < 2) {
            lastTwoAveraged.add(newCoord);
            lastTwoAveraged.add(newCoord);
        } else {
            lastTwoAveraged.remove(1);
            lastTwoAveraged.add(newCoord);
        }
        return newCoord;
    }

    public Float[] getAvgedCoords() {


        float avgX = 0;
        float avgY = 0;
        float avgZ = 0;

        for (int i = 0; i < lastTen.size(); i++) {
            avgX += lastTen.get(i)[0];
            avgY += lastTen.get(i)[1];
            avgZ += lastTen.get(i)[2];
        }
        avgX = avgX / lastTen.size();
        avgY = avgY / lastTen.size();
        avgZ = avgZ / lastTen.size();

        if (oldCoord != null) {
            oldCoord = newCoord;

        }
        newCoord = new Float[]{ avgX, avgY, avgZ};
        if (oldCoord == null) {
            oldCoord = newCoord;
        }

        if (lastTwoAveraged.size() < 2) {
            lastTwoAveraged.add(newCoord);
            lastTwoAveraged.add(newCoord);
        } else {
            lastTwoAveraged.remove(1);
            lastTwoAveraged.add(newCoord);
        }
        return newCoord;
    }

    public Float[] returnLastAvgCord() {
        lowPassFilter();
        return lastTwoAveraged.get(1);

    }

    //public double getError() {
   //     return this.currentMessage.getError();
   // }

    public int numberOfCoords() {
        return lastTen.size();
    }

    public void setColour(Color playerColour) {
        thisColour = playerColour;
    }

    public Color returnColor() {
        return thisColour;
    }

   // public void setMessage(LocationMessage message) {
   //     this.currentMessage = message;
   // }

   // public void setOtherPlayerMessage(LocationMessage lastMessage) {
   //     this.otherPlayerMessage = lastMessage;
   // }

 /**   public double calculateDistanceBetweenPlayers() {
        double distance = 0;
        distance =
                Math.sqrt(Math.pow((lastTen.get(0).getX()), 2) + Math.pow((lastTen.get(0).getY()), 2));
        return distance;
    }
**/
    private double caloriesBurnt(double distance) {
        return 0.08 * distance;
    }

    private void calculatePercentages() {
        //split the pitch into two areas, if in left, add 1 to left and vice versa.
        //After, % = (l/(l+r))*100

        double x = lastTen.get(0)[0];
        float minX_1 = 0;
        float maxX = 0;
       // for (int i = 0; i <boundaryCordinates.size(); i++) {
            if (minX_1 > boundaryCordinates[0]) {
                minX_1 = boundaryCordinates[0];
            }

            if (maxX < boundaryCordinates[0]) {
                maxX = boundaryCordinates[0];
            }

        //}
        float divider = maxX - ((maxX - minX_1) / 2);

        if (x < divider) {
            this.timesInLeft++;

        }

        if (x > divider) {
            this.timesInRight++;

        }

        double total = this.timesInLeft + this.timesInRight;

        double temp = this.timesInLeft / total;
        this.percentageInLeft = ((temp) * 100);
        temp =
                this.timesInRight / total;


        this.percentageInRight = ((temp) * 100);

    }

    private double addDistance() {
        double distance = 0;

        distance =
                Math.sqrt(Math.pow((lastTen.get(0)[0] - lastTen.get(1)[0]), 2) + Math.pow((lastTen.get(0)[1] - lastTen.get(1)[1]), 2));
        if (distance < 0.15) {
            distance = 0;
        }

        return distance;
    }

    private double averageSpeed() {

        return totalDistance / totalTime;

    }

    private double currentSpeed() {

        double time = lastTen.get(0)[3] - lastTen.get(1)[3];
        time =
                time / 1000;
        totalTime +=
                time;
        double distance = addDistance();


        return distance / time;
    }

    public double removeX() {

        return lastTen.get(1)[0];
    }

    public double removeY() {
        return lastTen.get(1)[1];
    }

    /**
     * @return the currentSpeed
     */
    public double getCurrentSpeed() {
        return currentSpeed;
    }

    /**
     * @return the totalDistance
     */
    public double getTotalDistance() {
        return totalDistance;
    }

    /**
     * @return the tagID
     */
    public int gettagID() {
        return tagID;
    }

    /**
     * @param tagID the tagID to set
     */
    public void settagID(int tagID) {
        this.tagID = tagID;
    }

    /**
     * @return the avgSpeed
     */
    public double getAvgSpeed() {
        return avgSpeed;
    }

    /**
     * @param statsX the statsX to set
     */
    public void setStatsX(double statsX) {
        this.statsX = statsX;
    }

    /**
     * @return the statsY
     */
    public double getStatsY() {
        return statsY;
    }

    /**
     * @param statsY the statsY to set
     */
    public void setStatsY(double statsY) {
        this.statsY = statsY;
    }

    /**
     * @return the statsY
     */
    public double getStatsX() {
        return statsX;
    }

    /**
     * @return the orderOfAppearence
     */
    public int getOrderOfAppearence() {
        return orderOfAppearence;
    }

    /**
     * @param orderOfAppearence the orderOfAppearence to set
     */
    public void setOrderOfAppearence(int orderOfAppearence) {
        this.orderOfAppearence = orderOfAppearence;
    }

    /**
     * @return the showPlayer
     */
    public boolean isShowPlayer() {
        return showPlayer;
    }

    /**
     * @param showPlayer the showPlayer to set
     */
    public void setShowPlayer(boolean showPlayer) {
        this.showPlayer = showPlayer;
    }

    /**
     * @return the caloriesBurnt
     */
    public double getCaloriesBurnt() {
        return caloriesBurnt;
    }

    /**
     * @return the percentageInLeft
     */
    public double getPercentageInLeft() {
        return percentageInLeft;
    }

    /**
     * @return the percentageInRight
     */
    public double getPercentageInRight() {
        return percentageInRight;
    }

    /**
     * @return the oldCoord
     */
    public Float[] getOldCoord() {
        if (oldCoord == null) {
            oldCoord = lastTen.get(0);
        }
        return oldCoord;
    }
}
